package com.service.business.member.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.service.business.member.controller.rep.MemberSignRep;
import com.service.business.member.dto.MemberSignData;
import com.service.business.member.dto.MemberStoreChange;
import com.service.business.member.service.MemberSignService;
import com.service.business.member.service.MemberStoreService;
import com.service.business.support.MemberStoreLockUtils;
import com.service.business.utils.DateUtil;
import com.service.core.constant.BusinessStatus;
import com.service.core.exception.CommonException;
import com.service.dao.enums.CoinsEnum;
import com.service.dao.enums.MemberJAType;
import com.service.dao.mapper.JournalAccountMapper;
import com.service.dao.mapper.MemberSignMapper;
import com.service.dao.model.JournalAccount;
import com.service.dao.model.MemberSign;
import com.service.dao.model.MemberStore;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Service("memberSignService")
@Transactional(readOnly = false)
@Slf4j
public class MemberSignServiceImpl extends ServiceImpl<MemberSignMapper, MemberSign> implements MemberSignService {
	@Autowired
	private JournalAccountMapper journalAccountMapper;
	@Autowired
	private MemberStoreService memberStoreService;
	@Autowired
	private MemberStoreLockUtils memberStoreLockUtils;

	private static final BigDecimal otherGiftPoints = new BigDecimal(3L);

	/**
	 * @param someday
	 * @Description: 根据传入的yyyy-MM 时间查询当月签到记录
	 * @Author: ty
	 * @Date: 2021/5/28 12:41
	 * @param: [memberId, someday]
	 * @return: java.util.List<com.service.business.member.controller.rep.MemberSignRep>
	 */
	@Override
	public MemberSignRep listByMemberIdAndSomeday(Integer memberId, Date someday) {
		MemberSignRep rep = new MemberSignRep();
		List<MemberSignData> list = new ArrayList<>();
		List<Date> dateList = getAllTheDateOfTheMonth(someday);

		dateList.parallelStream().forEach(item -> {
			MemberSignData signData = new MemberSignData();
			String currentStr = DateFormatUtils.format(item, "yyyy-MM-dd");
			Integer num = journalAccountMapper.checkByMemberAndTypeAndSomeday(memberId, currentStr, MemberJAType.getSignType());
			if(num > 0){
				signData.setIsSign(1);
			}else{
				signData.setIsSign(0);
			}

			signData.setDay(getDays(item));
			list.add(signData);
		});
		rep.setSignDataList(list);
		return rep;
	}

	/**
	 * @Description: 用户签到
	 * @Author: ty
	 * @Date: 2021/5/28 13:58
	 * @param: [memberId]
	 * @return: void
	 **/
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void sign(Integer memberId) {
		Date current = new Date();
		String currentStr = DateFormatUtils.format(current, "yyyy-MM-dd");
		Date yesterday = DateUtil.addDay(current, -1);
		String yesterdayStr = DateFormatUtils.format(yesterday, "yyyy-MM-dd");
		//获取用户签到记录
		MemberSign mySign = baseMapper.selectOne(new QueryWrapper<MemberSign>().lambda()
			.eq(MemberSign::getMemberId,memberId)
		);
		if(ObjectUtils.isEmpty(mySign)){
			mySign = new MemberSign();
			mySign.setMark(currentStr);
			mySign.setMemberId(memberId);
			mySign.setContinueSign(1);
			mySign.setCountSign(1);
			mySign.setCountContinueSign(1);
			baseMapper.insert(mySign);
		}
		Integer num = journalAccountMapper.checkByMemberAndTypeAndSomeday(memberId, currentStr, MemberJAType.getSignType());
		BigDecimal points = BigDecimal.ONE;
		if(num < 1){
			if(mySign.getMark().equals(yesterdayStr)){
				//连续签到
				mySign.setCountSign(mySign.getCountSign()+1);
				//今日签到
				if(mySign.getCountSign() == 7){
					points = points.add(otherGiftPoints);
					mySign.setCountSign(0);
				}
				mySign.setCountContinueSign(mySign.getCountContinueSign()+1);
			}else{
				mySign.setCountSign(1);
				mySign.setCountContinueSign(1);
			}
			mySign.setContinueSign(mySign.getContinueSign()+1);
			mySign.setMark(currentStr);
			MemberStore memberStore = memberStoreService.getMemberStore(memberId,CoinsEnum.POINTS.getName());
			boolean isLock = memberStoreLockUtils.lock(memberId,memberStore.getId());
			if(isLock){
				try{
					memberStoreService.changeMemberStore(
							MemberStoreChange.builder()
									.memberId(memberId)
									.coinsId(CoinsEnum.POINTS.getCode())
									.coinsName(CoinsEnum.POINTS.getName())
									.jaType(MemberJAType.DAILY_SIGN_ADD)
									.changeNum(points)
									.remark(currentStr + MemberJAType.DAILY_SIGN_ADD.getMsg() +"+"+points)
									.build());
					baseMapper.updateById(mySign);
				}finally {
					memberStoreLockUtils.unlock(memberId, CoinsEnum.POINTS.getCode());
				}
			}
		}else{
			throw new CommonException(BusinessStatus.ALREADY_SIGN.value(),"今日已签到");
		}
	}

	/**
	 * @param memberId
	 * @param someday
	 * @Description: 获取用户某天签到所得积分
	 * @Author: ty
	 * @Date: 2021/6/2 14:29
	 * @param: [memberId, someday]
	 * @return: java.math.BigDecimal
	 */
	@Override
	public BigDecimal getSomedayByMember(Integer memberId, Date someday) {
		String somedayStr = DateFormatUtils.format(someday, "yyyy-MM-dd");
		return journalAccountMapper.getSomedayIncome(memberId,MemberJAType.getSignType(),somedayStr);
	}

	/**
	 * @Description: 获取传入日期的本月数据
	 * @Author: ty
	 * @Date: 2021/5/28 14:21
	 * @param: [date]
	 * @return: java.util.List
	 **/
	private static List<Date> getAllTheDateOfTheMonth(Date date) {
		List<Date> list = new ArrayList();
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DATE, 1);
		int month = cal.get(Calendar.MONTH);
		while (cal.get(Calendar.MONTH) == month) {
			list.add(cal.getTime());
			cal.add(Calendar.DATE, 1);
		}
		return list;
	}

	/**
	 * @Description: 获取传入日期的本月数据
	 * @Author: ty
	 * @Date: 2021/5/28 14:21
	 * @param: [date]
	 * @return: java.util.List
	 **/
	private static int getDays(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		return cal.get(Calendar.DAY_OF_MONTH);
	}
}
